


#include "dexgel\dexgel.hpp"


#include <vector>
#include <fstream>
#include <iostream>
#include <glm/glm.hpp>
//#include <glm/gtc/matrix_projection.hpp>
#include <glm/gtc/matrix_transform.hpp>

#pragma comment(lib, "dexgel.lib")

#define PACKRGB(rendrer,g,b) \
	((unsigned int)((((0xff)&0xff)<<24)|(((rendrer)&0xff)<<16)|(((g)&0xff)<<8)|((b)&0xff)))

const int kCubeVertCount = 8; // Number of vertices in the cube
const int kCubeIndiceCount = 36; // Number of indices to define the cube as triangles

dexgel::Rendrer *rend;



//Sprite structures:
typedef struct { long col; unsigned short z; char vis, dir; } kv6voxtype;

typedef struct kv6data
{
	long leng, xsiz, ysiz, zsiz;
	float xpiv, ypiv, zpiv;
	unsigned long numvoxs;
	//long namoff;
	//kv6data *lowermip;
	kv6voxtype *vox;      //numvoxs*sizeof(kv6voxtype)
	unsigned long *xlen;  //xsiz*sizeof(long)
	unsigned short *ylen; //xsiz*ysiz*sizeof(short)
} kv6data;

void evilquit(const char* str)
{
	printf("%s", str);
	exit(EXIT_FAILURE);
}

//NOTE: should make this inline to getkv6!
static kv6data *loadkv6 (const std::string filename)
{
	std::ifstream fin(filename.c_str(),std::ios::binary);
	if( !fin.is_open() )
	{
		std::cout << "KV6 file" << filename << " not found!" << std::endl;

		fin.close();
		return NULL;
	}
	
	kv6data tk, *newkv6;
	long i;

	fin.read((char *)&tk,32);

	i = tk.numvoxs*sizeof(kv6voxtype) + tk.xsiz*4 + tk.xsiz*tk.ysiz*2;
	newkv6 = (kv6data *)malloc(i+sizeof(kv6data));
	if (!newkv6) { return(NULL); }
	if (((long)newkv6)&3) evilquit("getkv6 malloc not 32-bit aligned!");

	newkv6->leng = i+sizeof(kv6data);
	memcpy(&newkv6->xsiz,&tk.xsiz,28);
	//newkv6->namoff = 0;
	//newkv6->lowermip = 0;
	newkv6->vox = (kv6voxtype *)(((long)newkv6)+sizeof(kv6data));
	newkv6->xlen = (unsigned long *)(((long)newkv6->vox)+tk.numvoxs*sizeof(kv6voxtype));
	newkv6->ylen = (unsigned short *)(((long)newkv6->xlen) + tk.xsiz*4);

	fin.read((char *)newkv6->vox,i);
	
	return(newkv6);
}
//Set all bits in vbit from (x,y,z0) to (x,y,z1-1) to 1's
static void setzrange1 (long *lptr, long z0, long z1)
{
	long z, ze;
	if (!((z0^z1)&~31)) { lptr[z0>>5] |= ((~(-1<<z1))&(-1<<z0)); return; }
	z = (z0>>5); ze = (z1>>5);
	lptr[z] |= (-1<<z0); for(z++;z<ze;z++) lptr[z] = -1;
	lptr[z] |=~(-1<<z1);
}

dexgel::Mesh* genkv6(dexgel::Rendrer *rend, const kv6data *mdl)
{
	std::vector<dexgel::LitVertex> verts;

	int xsiz = mdl->xsiz;
	int ysiz = mdl->ysiz;
	int zsiz = mdl->zsiz;
	
	unsigned long *xlen = mdl->xlen;
	unsigned short *ylen = mdl->ylen;
	kv6voxtype *vox = mdl->vox;

	for (int x=0; x<xsiz; x++)
	{
		for (int y=0; y<ysiz; y++)
		{
			int columns_in_slab = ylen[x*ysiz+y];
			for(int i=0; i<columns_in_slab; i++)
			{
				kv6voxtype* startptr = &vox[i];
				
				int z = startptr->z;
				char visibility = startptr->vis; //Low 6 bits say if neighbor is solid or air
				bool face1 = (visibility >> 0) & 1; 
				bool face2 = (visibility >> 1) & 1; 
				bool face3 = (visibility >> 2) & 1; 
				bool face4 = (visibility >> 3) & 1; 
				bool face5 = (visibility >> 4) & 1; 
				bool face6 = (visibility >> 5) & 1; 

				char normal_idx = startptr->dir;

				float scaler = 0.5f;
				glm::mat4 cube_position = glm::translate( glm::mat4(1.0f), glm::vec3(+x*scaler - scaler*xsiz/2.f, + y*scaler - scaler*ysiz/2.f, -z*scaler + scaler*zsiz/2.f) );
				
				
				cube_position = glm::scale( cube_position, glm::vec3(scaler) );

				unsigned int color = startptr->col; 

				float gCubeVerts[] =
				{
					-0.5, -0.5, -0.5, 
					-0.5, 0.5, -0.5, 
					0.5, -0.5, -0.5, 
					0.5, -0.5, -0.5, 
					-0.5, 0.5, -0.5, 
					0.5, 0.5, -0.5,  
					0.5, -0.5, -0.5, 
					0.5, 0.5, -0.5,  
					0.5, -0.5, 0.5,  
					0.5, -0.5, 0.5,  
					0.5, 0.5, -0.5,  
					0.5, 0.5, 0.5, 
					0.5, -0.5, 0.5,  
					0.5, 0.5, 0.5, 
					-0.5, -0.5, 0.5, 
					-0.5, -0.5, 0.5, 
					0.5, 0.5, 0.5, 
					-0.5, 0.5, 0.5,  
					-0.5, -0.5, 0.5, 
					-0.5, 0.5, 0.5,  
					-0.5, -0.5, -0.5,
					-0.5, -0.5, -0.5, 
					-0.5, 0.5, 0.5,  
					-0.5, 0.5, -0.5, 
					-0.5, 0.5, -0.5, 
					-0.5, 0.5, 0.5,  
					0.5, 0.5, -0.5,  
					0.5, 0.5, -0.5,  
					-0.5, 0.5, 0.5,  
					0.5, 0.5, 0.5,
					-0.5, -0.5, -0.5, 
					0.5, -0.5, -0.5, 
					-0.5, -0.5, 0.5, 
					0.5, -0.5, -0.5, 
					0.5, -0.5, 0.5,  
					-0.5, -0.5, 0.5, 
				};

				// duplicating verts...
				for( int i=0; i<6*2*3*3; i+=1*3*3 )
				{
					glm::vec3 v1( gCubeVerts[i+0], gCubeVerts[i+1], gCubeVerts[i+2] );
					glm::vec3 v2( gCubeVerts[i+3], gCubeVerts[i+4], gCubeVerts[i+5] );
					glm::vec3 v3( gCubeVerts[i+6], gCubeVerts[i+7], gCubeVerts[i+8] );

					glm::vec3 n = glm::cross( (v2-v1), (v3-v1) );
					n = glm::normalize( n );


					dexgel::LitVertex vert1( glm::vec3( cube_position * glm::vec4(v1.x, v1.y, v1.z, 1.0f) ), n, color);
					dexgel::LitVertex vert2( glm::vec3( cube_position * glm::vec4(v2.x, v2.y, v2.z, 1.0f) ), n, color);
					dexgel::LitVertex vert3( glm::vec3( cube_position * glm::vec4(v3.x, v3.y, v3.z, 1.0f) ), n, color);
					verts.push_back( vert1 );
					verts.push_back( vert2 );
					verts.push_back( vert3 );
				}


			} // for cols in slab
			vox += columns_in_slab;

		}
	}
	dexgel::Mesh *m = rend->createMesh( &verts[0], verts.size() );
	
	return m;
}

dexgel::Mesh* loadKv6AsMesh(dexgel::Rendrer *rend, const std::string &filename)
{
	kv6data *model = loadkv6(filename);

	if ( model )
	{
		printf("successfully loaded %dx%dx%d model \n", model->xsiz, model->ysiz, model->zsiz );

	}else
	{
		return NULL;
	}
	dexgel::Mesh *m = genkv6(rend, model);
	if (model->vox)
	{
		int num_bytes = model->numvoxs*sizeof(kv6voxtype) + model->xsiz*4 + model->xsiz*model->ysiz*2 + sizeof(kv6data);
		printf("freeing %d kbytes\n", num_bytes/1024 );
		free(model);
		//free( model->vox ); // ptr was malloced at model! not vox!
	}
	return m;
}




